 /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bibliothequemultimedia;

import utils.Filtre;
import media.Media;
import dao.MediaDAO;
import dao.MusiqueDAO;
import dao.PhotoDAO;
import dao.VideoDAO;
import exception.AucunPluginException;
import exception.ChargementPluginException;
import exception.FichierDeSerialisationException;
import exception.PluginDejaIntegreException;
import exception.SerializableException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
import media.Musique;
import media.Photo;
import media.Video;
import plugins.MediaPluginInterface;
import plugins.ChargeurPlugin;
import utils.FilterFileChooser;

/**
 * Classe BibliothequeService qui représente les services fournis par
 * la bibliothèque multimedia.
 * @author Florian Minin & Khémon Beh
 */
public class BibliothequeService {

    //Constante contenant le nom du fichier de sérialisation
    final public static String FIC_SERIALISATION_GENERAL = "media.ser";
    final public static String FIC_SERIALISATION_PLUGINS = "plugins.ser";

    //Constante contenant les différentes extensions pour chaque type de média
    final public static Set<String> EXTENSIONS_PLUGIN = new TreeSet<String>(Arrays.asList(".jar"));
    private Map<Integer, MediaDAO> daoBibliotheque;
    private Map<String, String> listePlugins;
    private List<Filtre> filtresMedia;

    /**
     * Constructeur de la classe BibliothequeService
     * Initialise les différents DAO.
     */
    public BibliothequeService() {
        daoBibliotheque = new TreeMap<Integer, MediaDAO>();
        listePlugins = new TreeMap<String, String>();
        filtresMedia = new ArrayList<Filtre>();

        //De base, la musique, les photo et les video sont gérés
        daoBibliotheque.put(daoBibliotheque.size(), new MusiqueDAO());
        daoBibliotheque.put(daoBibliotheque.size(), new PhotoDAO());
        daoBibliotheque.put(daoBibliotheque.size(), new VideoDAO());

        //Initialisation des filtres de media
        filtresMedia.add(new Filtre(new FilterFileChooser("Fichiers audio", Musique.EXTENSIONS_AUDIO), Musique.TYPE_MEDIA_MUSIQUE));
        filtresMedia.add(new Filtre(new FilterFileChooser("Fichiers images", Photo.EXTENSIONS_IMAGE), Photo.TYPE_MEDIA_PHOTO));
        filtresMedia.add(new Filtre(new FilterFileChooser("Fichiers video", Video.EXTENSIONS_VIDEO), Video.TYPE_MEDIA_VIDEO));
    }

    /**
     * Enregistre les données des objets de l'application
     * dans le fichier de sérialisation FIC_SERIALISATION_GENERAL
     */
    public void serializeMedia() throws SerializableException{
        try {
            //Ouverture du fichier
            FileOutputStream fichier = new FileOutputStream(FIC_SERIALISATION_GENERAL);
            //Création de l'instance qui va sérialiser les objets
            ObjectOutputStream oos = new ObjectOutputStream(fichier);
            //Enregistrement dynamique des données
            //On parcourt l'ensemble des DAO de l'application et on enregistre
            //la map de données dans le fichier de sérialisation
            for (Entry<Integer, MediaDAO> mapDAOTemp : this.getAllDAO()) {
                //oos.writeObject(mapDAOTemp.getValue().getMapMedia());
                oos.writeObject(mapDAOTemp.getValue());
            }
            //Fermeture du fichier
            oos.close();
        } catch (java.io.IOException e) {
            throw new SerializableException();
        }
    }

    public void serializePluginMedia() throws FichierDeSerialisationException{
        try {
            //Ouverture du fichier
            FileOutputStream fichier = new FileOutputStream(FIC_SERIALISATION_PLUGINS);
            //Création de l'instance qui va sérialiser les objets
            ObjectOutputStream oos = new ObjectOutputStream(fichier);
            //Enregistrement dynamique des données
            //On parcourt l'ensemble des DAO de l'application et on enregistre
            //la map de données dans le fichier de sérialisation
            oos.writeObject(listePlugins);
            //Fermeture du fichier
            oos.close();
        } catch (java.io.IOException e) {
            throw new FichierDeSerialisationException();
        }
    }

    /**
     * Récupère les données contenues dans le fichier de sérialisation
     * FIC_SERIALISATION_GENERAL et les enregistre dans l'application actuelle
     */
    public void deserializeMedia() throws FichierDeSerialisationException{
        try {
            FileInputStream fichier = new FileInputStream(FIC_SERIALISATION_GENERAL);
            ObjectInputStream ois = new ObjectInputStream(fichier);
            //Récupération des données de manière dynamique
            //On parcourt l'ensemble des DAO de l'application et on leur ajoute
            //les map correspondantes a partir du fichier sérialisé
            for (Entry<Integer, MediaDAO> mapDAOTemp : this.getAllDAO()) {
                mapDAOTemp.setValue((MediaDAO) ois.readObject());
            }
            ois.close();
        } catch (IOException ioe) {
            throw new FichierDeSerialisationException();
        } catch (ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
        }
    }

    public MediaPluginInterface[] deserializePluginMedia() throws AucunPluginException, ChargementPluginException {
        try {
            FileInputStream fichier = new FileInputStream(FIC_SERIALISATION_PLUGINS);
            ObjectInputStream ois = new ObjectInputStream(fichier);
            //Récupération des données de manière dynamique
            //On parcourt l'ensemble des DAO de l'application et on leur ajoute
            //les map correspondantes a partir du fichier sérialisé
            listePlugins = ((Map<String, String>) ois.readObject());
            ois.close();
            ChargeurPlugin manager = new ChargeurPlugin(getListePlugin());
            MediaPluginInterface[] plugins = manager.loadAllMediaPlugins();
            for (int i = 0; i < plugins.length; i++) {
                filtresMedia.add(plugins[i].getFiltreMedia());
                daoBibliotheque.put(daoBibliotheque.size(), plugins[i].getDAOMedia());
            }
            return plugins;
        //Les returns new permettent d'éviter de tester si on passe un objet
        //null. On retourne des tableau vides
        } catch (IOException ioe) {
            throw new AucunPluginException();
        } catch (Exception e){
            throw new ChargementPluginException();
        }
    }

    /**
     * Accesseur d'un des DAO selon le type
     * @return
     */
    public MediaDAO getDAO(String typeDAO) {
        int indiceDAO = -1;
        for(int i=0;i<daoBibliotheque.size();i++){
            if(daoBibliotheque.get(i).getTypeMedia().equals(typeDAO)){
                indiceDAO = i;
                break;
            }
        }
        return daoBibliotheque.get(indiceDAO);
    }

    public Set<String> getAllTypes() {
        Set<String> types = new TreeSet<String>();
        for(int i=0;i<daoBibliotheque.size();i++){
            types.add(daoBibliotheque.get(i).getTypeMedia());
        }
        return types;
    }

    public Set<Entry<Integer, MediaDAO>> getAllDAO() {
        return daoBibliotheque.entrySet();
    }

    /**
     * Retour un ensemble afin de faciliter le parcours
     * des filtres
     * @return <tt>Set</tt> contenant l'ensemble des Filtre
     */
    public List<Filtre> getAllFilters() {
        return filtresMedia;
    }

    public void integrerPlugin(MediaPluginInterface plugin, String emplacementPlugin) throws PluginDejaIntegreException {
        if (getAllTypes().contains(plugin.getTypeMedia())) {
            throw new PluginDejaIntegreException();
        } else {
            daoBibliotheque.put(daoBibliotheque.size(), plugin.getDAOMedia());
            listePlugins.put(plugin.getTypeMedia(), emplacementPlugin);
            filtresMedia.add(plugin.getFiltreMedia());
        }
    }

    public List<String> getListePlugin() {
        return new ArrayList(listePlugins.values());
    }

    public Map<Integer, MediaDAO> getBibliDAO(){
        return daoBibliotheque;
    }
    public void setListFiltresMedia(List<Filtre> l){
        filtresMedia = l;
    }
}
